package Algorithm.interview;

/**
 * @Author self
 * @Date 2024/9/12 20:51
 * @Describe “三数之和”问题是经典的算法题之一。题目的要求通常是：给定一个数组，找出其中的三个数，
 * 使得它们的和为零，并且不重复。常见的解法是基于排序和双指针技巧。
 *
 * 给定一个包含 n 个整数的数组 nums，判断 nums 中是否存在三个元素 a, b, c，使得它们的和为 0。
 * 找出所有满足条件且不重复的三元组。
 *
 * 解题思路：
 * 排序：首先将数组进行排序，这样方便使用双指针来查找符合条件的三元组。
 * 遍历：遍历数组，将每个元素固定为其中一个元素，然后使用双指针在剩余的数组中寻找其他两个数，使得三数之和为零。
 * 去重：为了防止结果中的重复三元组，我们需要在遍历和双指针移动时跳过重复的元素。
 */
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;

public class ThreeSum {
    public static List<List<Integer>> threeSum(int[] nums) {
        List<List<Integer>> result = new ArrayList<>();
        Arrays.sort(nums);  // 排序

        for (int i = 0; i < nums.length - 2; i++) {
            // 跳过重复元素
            if (i > 0 && nums[i] == nums[i - 1]) {
                continue;
            }

            // 双指针法
            int left = i + 1;  // 左指针
            int right = nums.length - 1;  // 右指针

            while (left < right) {
                int sum = nums[i] + nums[left] + nums[right];
                if (sum == 0) {
                    // 找到符合条件的三元组
                    result.add(Arrays.asList(nums[i], nums[left], nums[right]));

                    // 跳过重复元素
                    while (left < right && nums[left] == nums[left + 1]) {
                        left++;
                    }
                    while (left < right && nums[right] == nums[right - 1]) {
                        right--;
                    }

                    left++;
                    right--;
                } else if (sum < 0) {
                    left++;  // 如果和小于0，移动左指针
                } else {
                    right--;  // 如果和大于0，移动右指针
                }
            }
        }

        return result;
    }

    public static void main(String[] args) {
        int[] nums = {-1, 0, 1, 2, -1, -4};
        List<List<Integer>> result = threeSum(nums);
        for (List<Integer> triplet : result) {
            System.out.println(triplet);
        }
    }
}

